
//  回调函数类型
type Callback = (target:Element,inView:boolean) =>void
// 进入视窗的监听函数  
type ObserveFn  = (target:Element,callback:(isView:boolean)=>void) =>()=>void
/**
 *  通过 IntersectionObserver来获取 DOM元素的监听函数  
 */
function getObserveFn(root?:Element):ObserveFn {
/**
 * 当一个IntersectionObserver对象被创建时，其被配置为监听根中一段给定比例的可见区域。
 * 一旦 IntersectionObserver 被创建，则无法更改其配置，所以一个给定的观察者对象只能用来监听可见区域的特定变化值；
 * 然而，你可以在同一个观察者对象中配置监听多个目标元素。
 */
 const queue  = [] as Callback[]; // 类型断言 表示queue中的元素一定是Callback类型
 const observer = new IntersectionObserver(entries =>{
      entries.forEach(entry =>{
        const isView =  entry.intersectionRatio>=0.5 //   表示元素在可视区域出现的比例
        // 将isView传递给queue 并且执行  ps：这里有点疑问 为什么要在进行遍历 什么时候这个数组中会有多个元素
        queue.slice().forEach(fn=>fn(entry.target,isView))    
    
    })
 },{
     root,
     rootMargin:'0px',
    threshold:0.5
 })
   const observe :ObserveFn = (target,callback)=>{
   observer.observe(target); // 当target的可见性发生变化时，就会执行IntersectionObserver的回调函数
   const handle:Callback = (t,inView) =>{
       if(t===target){
           callback(inView);
       } // 在observer的元素集中 会包裹多个元素 选出我们需要监听的目标元素 执行所对应的callback
   } 
   queue.push(handle);
    // 返回一个取消监听的函数  
    return ():void =>{
       observer.unobserve(target);
       const idx = queue.indexOf(handle);
       queue.splice(idx);
    }

  }
  return observe;
}
export const Observer = getObserveFn();